package com.usefullc.user.service.interceptor;

import com.usefullc.common.constants.SystemConstant;
import com.usefullc.common.enums.AppTypeEnum;
import com.usefullc.common.enums.YesNoEnum;
import com.usefullc.common.exception.BizException;
import com.usefullc.system.service.AbstractService;
import com.usefullc.common.user.OnlineUser;
import com.usefullc.common.user.OnlineUserManager;
import com.usefullc.common.util.MapUtils;
import com.usefullc.system.service.component.SystemConfigComponent;
import com.usefullc.system.service.interceptor.AspectProcess;
import com.usefullc.user.domain.AuthRes;
import com.usefullc.user.domain.Role;
import com.usefullc.user.query.AuthResQuery;
import com.usefullc.user.query.RoleQuery;
import com.usefullc.user.service.AuthResService;
import com.usefullc.user.service.RoleService;
import com.usefullc.user.service.UserService;
import com.usefullc.user.service.component.UserManager;
import com.usefullc.user.vo.UserVo;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.stream.Collectors;

//import com.usefullc.user.service.RoleAuthResService;

/**
 * @author: Sampson
 * @date: 2022-01-10 13:44
 */
@Component
public class AuthAspectProcess extends AbstractService implements AspectProcess {

    @Value("${auth.check}")
    private boolean authCheck;

    @Autowired
    private UserService userService;

    @Autowired
    private AuthResService authResService;

    @Autowired
    private RoleService roleService;

//    @Autowired
//    private RoleAuthResService roleAuthResService;

    @Autowired
    private SystemConfigComponent systemConfigComponent;

    private Map<Long, Set<AuthResObj>> roleAuthResMap = new HashMap<>();
    private Map<String, AuthResObj> riskUrlAuthResMap = new HashMap<>();
    private Map<String, AuthResObj> repeatUrlAuthResMap = new HashMap<>();
    private Set<String> whiteUrls = new HashSet<>();


    @EventListener(ApplicationReadyEvent.class)
    public void initData() {
        roleAuthResMap.clear();
        //获取所有可用资源
        AuthResQuery authResQuery = new AuthResQuery();
        String appName = systemConfigComponent.getAppName();
        List<String> appTypeList = new ArrayList<>();
        appTypeList.add(appName);
        appTypeList.add(AppTypeEnum.SYSTEM.getCode());
        appTypeList.add(AppTypeEnum.USER.getCode());
        authResQuery.setAppTypeList(appTypeList);
        authResQuery.setStatus(YesNoEnum.YES.getCode());
        List<AuthRes> authResList = authResService.findAll(authResQuery);

        if (CollectionUtils.isEmpty(authResList)) {
            return;
        }
        Map<Long, AuthResObj> authResMap = authResList.stream().filter(x -> x.getAuthCheck()).collect(Collectors.toMap(AuthRes::getId, authRes -> {
            AuthResObj authResObj = new AuthResObj();
            authResObj.setCode(authRes.getCode());
            authResObj.setUrl(authRes.getUrl());
            return authResObj;
        }));


        riskUrlAuthResMap = authResList.stream().filter(x -> x.getRiskCheck()).collect(Collectors.toMap(AuthRes::getUrl, authRes -> {
            AuthResObj authResObj = new AuthResObj();
            authResObj.setCode(authRes.getCode());
            authResObj.setUrl(authRes.getUrl());
            authResObj.setRiskCheck(authRes.getRiskCheck());
            authResObj.setRiskCheckCondition(authRes.getRiskCheckCondition());
            return authResObj;
        }));

        repeatUrlAuthResMap = authResList.stream().filter(x -> x.getRepeatCheck()).collect(Collectors.toMap(AuthRes::getUrl, authRes -> {
            AuthResObj authResObj = new AuthResObj();
            authResObj.setCode(authRes.getCode());
            authResObj.setUrl(authRes.getUrl());
            authResObj.setRiskCheck(authRes.getRepeatCheck());
            return authResObj;
        }));

        whiteUrls = authResList.stream().filter(x -> !x.getAuthCheck()).map(x -> x.getUrl()).collect(Collectors.toSet());

        //手动加入
        whiteUrls.add("/user/user/getImgCode");
//        whiteUrls.add("/user/user/login");
//        whiteUrls.add("/user/user/logout");
//        whiteUrls.add("/system/common/res");
        whiteUrls.add("/tools/initData");
        whiteUrls.add("/task/test");
        whiteUrls.add("swagger-ui.html");
        whiteUrls.add("/swagger-resources");
        whiteUrls.add("v2/api-docs");
        whiteUrls.add("/liveStatus");
        whiteUrls.add("/readyStatus");
        whiteUrls.add("/redirectHttpStatus");
//        whiteUrls.add("/user/authRes/getAuthResByCurrentUser");


        //建立角色资源对应关系
//        RoleAuthResQuery roleAuthResQuery = new RoleAuthResQuery();

        List<Role> roleList = roleService.findAll(new RoleQuery());
        List<AuthRes> dataList = new ArrayList<>();
        for (Role role : roleList) {
            List<AuthRes> resList = role.getAuthResList();
            for (AuthRes authRes : resList) {
                if (!dataList.contains(authRes)) {
                    MapUtils.putSetElement(roleAuthResMap, role.getId(), authResMap.get(authRes.getId()));
                }
            }
        }

//        //排序
//        Collections.sort(dataList, Comparator.comparingInt(AuthRes::getOrderNo));
//        for (AuthRes authRes : dataList) {
//            MapUtils.putSetElement(roleAuthResMap,roleId,authResMap.get(authResId));
//        }
//        List<RoleAuthRes> roleAuthResList = roleAuthResService.findAll(roleAuthResQuery);
//        if (CollectionUtils.isEmpty(roleAuthResList)) {
//            return;
//        }
//        for (RoleAuthRes roleAuthRes : roleAuthResList) {
//            Long roleId = roleAuthRes.getRoleId();
//            Long authResId = roleAuthRes.getAuthResId();
//            AuthResObj authResObj = authResMap.get(authResId);
//            if(authResObj == null){
//                continue;
//            }
//
//        }
    }

    public boolean checkAuth(HttpServletRequest request) {
        try {
            //不要检查
            if (!authCheck) {
                return true;
            }
            String requestURI = request.getRequestURI();
            if(StringUtils.containsIgnoreCase(requestURI,"/system/common/res")){
                requestURI = "/system/common/res";

            }
            if (whiteUrls.contains(requestURI)) {
                return true;
            }

            //现在都在数据中去标记
            UserVo loginUser = userService.getLoginUser(request);
            if (loginUser == null) {
                throw new BizException(SystemConstant.ResponseCode.NOT_LOGIN, "请登录", false);
            }

            //将当前访问用户放入threadLocal
            UserManager.setLoginUser(loginUser);
            OnlineUser onlineUser = new OnlineUser(loginUser.getId(), loginUser.getUserName());
            OnlineUserManager.setLoginUser(onlineUser);

            //暂时默认get请求都通过,后续通过资源做标记，获取所有资源去匹配
//        if (request.getMethod().equalsIgnoreCase(HttpMethod.GET.toString())) {
//            return true;
//        }

            List<Long> roleIds = loginUser.getRoleIds();
            if (CollectionUtils.isEmpty(roleIds)) {
                throw new BizException("user role is null");
            }

            for (Long roleId : roleIds) {
                Set<AuthResObj> authResSet = roleAuthResMap.get(roleId);
                if (CollectionUtils.isEmpty(authResSet)) {
                    continue;
                }
                String finalRequestURI = requestURI;
                boolean isMatch = authResSet.stream().anyMatch(x -> x != null && StringUtils.equals(x.getUrl(), finalRequestURI));
                if (isMatch) {
                    return true;
                }
            }
            return false;


        } catch (Exception e) {
            throw e;
        }
    }


//    public Map<String, AuthResObj> getRiskUrlAuthResMap() {
//        return riskUrlAuthResMap;
//    }
//
//    public Map<String, AuthResObj> getRepeatUrlAuthResMap() {
//        return repeatUrlAuthResMap;
//    }

    @Override
    public void process(ProceedingJoinPoint joinPoint, HttpServletRequest request) {
        boolean checkAuthState = this.checkAuth(request);
        if (!checkAuthState) {
            throw new BizException(SystemConstant.ResponseCode.NOT_AUTHORITY, "没有权限", false);
        }

    }

    @Override
    public void clean() {
        OnlineUserManager.clean();
        UserManager.clean();
    }


//    public  Set<AuthResObj> findAuthResByRoleIds(List<Long> roleIds){
//        Set<AuthResObj> authResObjSet = new HashSet<>();
//        for (Long roleId : roleIds) {
//            Set<AuthResObj> authResObjs = roleAuthResMap.get(roleId);
//            authResObjSet.addAll(authResObjs);
//        }
//        return authResObjSet;
//    }
}
